package club.jdiy.core;

import club.jdiy.core.ex.JDiyException;
import club.jdiy.core.sql.Rs;
import club.jdiy.core.storage.*;
import club.jdiy.utils.CookieUtils;
import club.jdiy.utils.JsonUtils;
import club.jdiy.utils.StringUtils;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;

/**
 * JDiy Http请求上下文父类.
 *
 * @author ziquee(子秋) QQ号:39886616 主页: http://www.jdiy.club
 * @version 20200809
 */
@SuppressWarnings("ALL")
abstract class HttpContext extends Context implements StoreAware {
    public HttpServletRequest getRequest() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return servletRequestAttributes.getRequest();
    }

    public HttpServletResponse getResponse() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return servletRequestAttributes.getResponse();
    }


    public String getContextPathURL() {
        if (StringUtils.hasText(jDiyProperties.getBaseUrl())) return jDiyProperties.getBaseUrl();
        try {
            HttpServletRequest request = getRequest();
            if (request.getServerPort() == 443)
                return String.format("https://%s%s", request.getServerName(), request.getContextPath());
            else if (request.getServerPort() == 80)
                return String.format("http://%s%s", request.getServerName(), request.getContextPath());
            else
                return String.format("http://%s:%d%s", request.getServerName(), request.getServerPort(), request.getContextPath());
        } catch (Exception e) {
            return "";
        }
    }

    public String getIp() {
        HttpServletRequest request = getRequest();
        String ip = request.getHeader("x-forwarded-for");
        for (String s : Arrays.asList("X-Real-Ip", "Proxy-Client-IP", "WL-Proxy-Client-IP", "http_client_ip", "HTTP_X_FORWARDED_FOR")) {
            if (ip == null || "".equals(ip) || "null".equals(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader(s);
            }
        }
        if (ip == null || "".equals(ip) || "null".equals(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip != null && ip.contains(",")) {
            ip = ip.substring(0, ip.indexOf(",")).trim();
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        return ip;
    }

    public String getCookie(String name) {
        return CookieUtils.getCookie(getRequest(), jDiyProperties.getAppid() + "_" + name);
    }

    public void setCookie(String name, String value) {
        CookieUtils.setCookie(getRequest(), getResponse(), jDiyProperties.getAppid() + "_" + name, value, -1);
    }

    public void setCookie(String name, String value, int expiry) {
        CookieUtils.setCookie(getRequest(), getResponse(), jDiyProperties.getAppid() + "_" + name, value, expiry);
    }

    public InputStream getResourceAsStream(String location) throws IOException {
        DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
        Resource res = resourceLoader.getResource(location);
        return res.getInputStream();
    }

    public Store getStore(String storeBucket, String id) {
        if (!StringUtils.hasText(storeBucket)) storeBucket = "entity";
        if (!StringUtils.hasText(id)) id = "0";//readonly for transient Entity Objects.
        String dataId = storeBucket + "_" + id;
        Rs rs = getDao().rs("jdiy_store", dataId);
        Store store = null;
        if (rs.isNew()) {
            if (jDiyProperties.getStore().getType() == StoreType.kodo) {
                store = new KodoStore(
                        jDiyProperties.getStore().getKodo(),
                        new StoreMetaData(StoreType.kodo, jDiyProperties.getStore().getKodo().getBucket(), new HashMap<>())
                        , storeBucket, id
                );
            } else if (jDiyProperties.getStore().getType() == StoreType.oss) {
                store = new OssStore(
                        jDiyProperties.getStore().getOss(),
                        new StoreMetaData(StoreType.oss, jDiyProperties.getStore().getKodo().getBucket(), new HashMap<>())
                        , storeBucket, id
                );
            }else if (jDiyProperties.getStore().getType() == StoreType.minio) {
                store = new MinioStore(
                        jDiyProperties.getStore().getMinio(),
                        new StoreMetaData(StoreType.minio, jDiyProperties.getStore().getKodo().getBucket(), new HashMap<>())
                        , storeBucket, id
                );
            }
        } else {
            try {
                StoreMetaData storeMetaData = JsonUtils.parse(rs.getString("data"), StoreMetaData.class);
                if (storeMetaData.getType() == StoreType.kodo)
                    store = new KodoStore(jDiyProperties.getStore().getKodo(), storeMetaData, storeBucket, id);
                else if (storeMetaData.getType() == StoreType.oss)
                    store = new OssStore(jDiyProperties.getStore().getOss(), storeMetaData, storeBucket, id);
                else if (storeMetaData.getType() == StoreType.minio)
                    store = new MinioStore(jDiyProperties.getStore().getMinio(), storeMetaData, storeBucket, id);
            } catch (Exception e) {
                e.printStackTrace();
                throw new JDiyException("初始化存储储对象失败. " + e.getMessage());
            }
        }
        if (store == null) store = new FileStore(getContextPathURL(), getUploadDir(), storeBucket, id);
        return (Store) Proxy.newProxyInstance(
                HttpContext.class.getClassLoader(),
                store.getClass().getInterfaces(),
                new StoreHandler(this.getDao(), store, dataId)
        );
    }
}
